#include "stdafx.h"
#include <boost/algorithm/string.hpp>
#include "../vfs/DirectoryLibrary.h"
#include "../vfs/SlfLibraryLocation.h"

namespace ja2{ namespace vfs
{
	SlfLibraryLocation::SlfLibraryLocation(boost::filesystem::path const &LibraryPath, boost::filesystem::path const &MountPoint)
		: UncompressedLibraryLocation(LibraryPath, MountPoint), m_LibraryFile(LibraryPath.string(), std::ios_base::binary)
	{
		// File must be opened
		assert(!m_LibraryFile.fail());
		// Set exception throwing
		m_LibraryFile.exceptions(std::ios_base::failbit | std::ios_base::eofbit);
		// Size of file name
		static const size_t FILENAME_SIZE = 256;
		// Size of library header
		static const size_t LIB_HEADER_SIZE = 532;
		// Size of dir entry
		static const size_t DIR_ENTRY_SIZE = 280;
		// Buffer for string
		char buffer[2048];
		char *p_buffer = buffer;
		// Read lib header
		m_LibraryFile.read(p_buffer, LIB_HEADER_SIZE);
		// Skip library name
		p_buffer += FILENAME_SIZE;
		// Get library path 
		std::string lib_path(p_buffer);
		// Remove trailing '/'
		boost::algorithm::erase_last(lib_path, "\\");
		boost::algorithm::replace_all(lib_path, "\\", "/");
		boost::algorithm::to_upper(lib_path);
		p_buffer += FILENAME_SIZE;
		// Get entries
		int32_t entry_size;
		std::memcpy(&entry_size, p_buffer, 4);
		// Get library path
		boost::filesystem::path const library_path = (!lib_path.empty() ? lib_path : boost::filesystem::path());
		// Set new mount point
		{
			boost::filesystem::path const mount_point = get_mount_point();
			set_mount_point(mount_point.empty() ? library_path : mount_point / library_path);
		}
		// Place the file pointer at the beginning of the file headers ( they are at the end of the file )
		m_LibraryFile.seekg(-std::ifstream::off_type(entry_size * DIR_ENTRY_SIZE), std::ios_base::end);
		for(int32_t i = 0; i < entry_size; ++i)
		{
			p_buffer = buffer;
			// Get dir file name
			m_LibraryFile.read(p_buffer, DIR_ENTRY_SIZE);
			std::string dir_file_name(p_buffer);
			boost::algorithm::replace_all(dir_file_name, "\\", "/");
			p_buffer += FILENAME_SIZE;
			// Get offset
			std::uint32_t offset;
			memcpy(&offset, p_buffer, 4);
			p_buffer += 4;
			// Get length
			std::uint32_t length;
			memcpy(&length, p_buffer, 4);
			p_buffer += 4;
			// Get state
			std::uint8_t state;
			memcpy(&state, p_buffer, 1);
			++p_buffer;
			// File is ok
			if(state == 0)
			{
				// Get the whole path to file
				boost::filesystem::path const dir_file_path(dir_file_name);
				// Get dir section
				boost::filesystem::path const o_dir = dir_file_path.parent_path();
				// Get file name
				boost::filesystem::path const o_file = dir_file_path.filename();
				// Get current mount point
				boost::filesystem::path lib_mount_point = get_mount_point();
				// Add directory path of item if dir is valid
				if(!o_dir.empty())
					lib_mount_point /= o_dir;
				// Get the directory location for path
				DirectoryPtr_t p_library_dir;
				// Directory exist
				if(dir_exist(lib_mount_point))
					p_library_dir = get_dir(lib_mount_point);
				// Create new directory
				else
				{
					p_library_dir.reset(new DirectoryLibrary(lib_mount_point, lib_mount_point));
					add_directory(lib_mount_point, p_library_dir);
				}
				// Create file descriptor and add it to directory
				p_library_dir->add_file(FileDescriptorPtr_t(new FileDescriptorLibrary(offset, offset + length, o_file, &m_LibraryFile)));
			}
		}
	}
} /*vfs*/} /*ja2*/